#include "login_connect_task.h"
#include <core/QbLogger.h>
#include <core/system/thread_wrapper.h>
#include <qbkernel/include/qb_base.h>

#ifndef _MSC_VER
#include <arpa/inet.h>
#endif

namespace qb
{
    CLoginConnectTask::CLoginConnectTask()
        : m_pThread(NULL)
		, m_uThreadId(0)
    {
    }

    CLoginConnectTask::~CLoginConnectTask()
    {
        if (IsRunning())
        {
            Cleanup();
        }
    }

    void CLoginConnectTask::StartImpl()
    {
        StartConnecting();
    }

    void CLoginConnectTask::TerminateImpl()
    {
        Cleanup();
    }

	void CLoginConnectTask::OnNetStatus(int32_t status)
	{
		OnConnect(status);
	}

    void CLoginConnectTask::OnTimeout()
    {
        log_debug("connect LoginServer timeout");
		StopThread();
		NotifyFailed(loginData::instance().GetCurrentStatus(), eNetError_ConnectServerTimeout);
    }

	bool CLoginConnectTask::ThreadCallback(void* args)
	{
		CLoginConnectTask* pConnectTask = (CLoginConnectTask*)args;
		QB_CHECK_RETURN_BOOL_ASSERT1(pConnectTask);

		return pConnectTask->ThreadProcess();
	}

    bool CLoginConnectTask::ThreadProcess()
    {
		if (eNetStatus_ConnectingLogin == loginData::instance().GetCurrentStatus())
		{
			if (!Connect(loginData::instance().GetServerLoginAddress()))
			{
				log_error(
					"%s can't connect LoginServer", __FUNCTION__);
			}
		}
		else if (eNetStatus_ConnectingGW == loginData::instance().GetCurrentStatus())
		{
			if (!Connect(loginData::instance().GetGatewayLoginAddress()))
			{
				log_error(
					"%s can't connect LoginServer", __FUNCTION__);
			}
		}

        return false;
    }

    void CLoginConnectTask::StartConnecting()
    {
		if (eNetStatus_None == loginData::instance().GetCurrentStatus())
		{
			// 更新当前步骤
			loginData::instance().SetCurrentStatus(eNetStatus_ConnectingLogin);

			// 通知observers当前的登录步骤
			NotifyLoginStep(eNetStatus_ConnectingLogin, 0);
		}
		else if (eNetStatus_VerifyLogin == loginData::instance().GetCurrentStatus())
		{
			// 更新当前步骤
			loginData::instance().SetCurrentStatus(eNetStatus_ConnectingGW);

			// 通知observers当前的登录步骤
			NotifyLoginStep(eNetStatus_ConnectingGW, 0);
		}

		// 开始连接线程
		if (!StartThread())
		{
			NotifyFailed(loginData::instance().GetCurrentStatus(), (short)eNetErrorCode::eNetError_ConnectServerError);
			return;
		}

		log_debug("connect verify server step [%s:%u]",  
			loginData::instance().GetServerLoginAddress().strIPAdress.c_str(), loginData::instance().GetServerLoginAddress().uPort);
    }

	bool CLoginConnectTask::StartThread()
	{
		if (m_pThread)
		{
			log_error("%s stop the exist thread");
			StopThread();
		}

		m_pThread = ThreadWrapper::CreateThread(ThreadCallback, this, 
			kNormalPriority, "LoginBaseTaskThreadCallback");
		if (!m_pThread)
		{
			log_error("thread not created");
			return false;
		}

		if (!m_pThread->Start(m_uThreadId))
		{
			log_error("thread not start");

			// delete the thread object
			ThreadWrapper* pThread = m_pThread;
			m_pThread = NULL;
			delete pThread;

			NotifyFailed(loginData::instance().GetCurrentStatus(), (short)eNetErrorCode::eNetError_CreateThreadFailed);

			return false;
		}

		return true;
	}

	void CLoginConnectTask::StopThread()
	{
		ThreadWrapper* tmpPtr = m_pThread;
		QB_CHECK_RETURN_VOID1(tmpPtr);

		m_pThread = NULL;
		tmpPtr->SetNotAlive();

		int32_t nTryCount = 6;
		while (--nTryCount >= 0)
		{
			if (tmpPtr->Stop())
			{
				delete tmpPtr;
				break;
			}
		}

		// error
		if (nTryCount < 0)
		{
			bool bForce = false;
			tmpPtr->Stop(bForce);
			if (bForce)
			{
				delete tmpPtr;
			}

			log_warning("stop thread failed, and we force terminate it");
		}
	}

	bool CLoginConnectTask::Connect(const tIPAdressPort& ipAddressPort)
	{
		return qbBase::getMessageKernel()->Connect(loginData::instance().ConnectID(), ipAddressPort.strIPAdress.c_str(), ipAddressPort.uPort) == 0 ? true : false;
	}

	void CLoginConnectTask::OnConnect(int32_t status)
	{
		// print log
		switch (status)
		{
		case kConnectTimeout:
			log_debug("connect timeout");
			break;
		case kConnectError:
			log_debug("network error");
			break;
		case kConnectConnectFailed:
			log_debug("connect failed");
			break;
		default:
			break;
		}

		// 停止时钟
		StopTaskTimer();

		// 停止连接线程
		StopThread();

		if (kConnectConnected == status)
		{
			if (eNetStatus_ConnectingLogin == loginData::instance().GetCurrentStatus())
			{
				// 更新当前步骤
				loginData::instance().SetCurrentStatus(eNetStatus_ConnectedLogin);

				// 通知observers当前的登录步骤
				NotifyLoginStep(eNetStatus_ConnectedLogin, 0);
			}
			else if (eNetStatus_ConnectingGW == loginData::instance().GetCurrentStatus())
			{
				// 更新当前步骤
				loginData::instance().SetCurrentStatus(eNetStatus_ConnectedGW);

				// 通知observers当前的登录步骤
				NotifyLoginStep(eNetStatus_ConnectedGW, 0);
			}

			NotifyFinished();
		}
		else
		{
			NotifyFailed(loginData::instance().GetCurrentStatus(), (short)eNetErrorCode::eNetError_ConnectServerError);
		}
	}

	void CLoginConnectTask::Disconnect()
	{
		qbBase::getMessageKernel()->CloseConnect(loginData::instance().ConnectID());
	}

    void CLoginConnectTask::Cleanup()
    {
    //    Disconnect();
        StopTaskTimer();
        StopThread();
    }
}
